package cn.xie.blog.serverutil.util;

import cn.xie.blog.model.common.enums.response.ResponseCodeEnum;
import cn.xie.blog.model.common.ttl.UserContext;
import cn.xie.blog.serverutil.constant.jwt.JwtContants;
import cn.xie.blog.serverutil.exception.BlogException;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.jackson.io.JacksonDeserializer;
import io.jsonwebtoken.security.Keys;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @description: JWT 工具类
 * @author: xiaoxie
 * @date: 2025/5/2 下午1:34
 * @param:
 * @return:
 **/
@Component
@RequiredArgsConstructor
public class JwtUtil {
    private static final Logger log = LoggerFactory.getLogger(JwtUtil.class);
    /**
     * 生成Token令牌
     *
     * @return 令牌Token
     */
    public String generateToken(String username, UserContext userContext) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("sub", JwtContants.SUBJECT);
        claims.put("created", new Date());
        claims.put("username", username);
        claims.put("userContext", JSONUtil.toJsonStr(userContext));
        log.info("userContext 类型:{}", claims.get("userContext").getClass());
        return getJwtBuilder(claims);
    }

    /**
     * 从token中获取username
     *
     * @param token 令牌
     * @return 用户名
     */
    public String getUserNameFromToken(String token) {
        String name;
        try {
            Claims claims = getClaimsFromToken(token);
            name = claims.get("username", String.class);
        } catch (Exception e) {
            name = null;
        }
        return name;
    }
    /**
     * @description: 从token中获取 用户上下文
     * @author: xiaoxie
     * @date: 2025/5/2 下午5:44
     * @param: [token]
     * @return: java.lang.String
     **/
    public String getUserContextFromToken(String token) {
        String userContextJson;
        try {
            Claims claims = getClaimsFromToken(token);
            userContextJson = claims.get("userContext", String.class);
        } catch (Exception e) {
            userContextJson = null;
        }
        return userContextJson;
    }
    /**
     * 从token中获取数据声明claim
     *
     * @param token 令牌token
     * @return 数据声明claim
     */
    public Claims getClaimsFromToken(String token) {
        try {
            SecretKey key = getSecretKey();
            return Jwts.parser()
                    .verifyWith(getSecretKey())
                    .build()
                    .parseSignedClaims(token)
                    .getPayload(); // 获取- Payload(有效载荷）
        } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) {
            log.error("token解析错误", e);
            throw new IllegalArgumentException("Token invalided.");
        }
    }

    /**
     * 判断token是否过期
     *
     * @param token 令牌
     * @return 是否过期：已过期返回true，未过期返回false
     */
    public Boolean isTokenExpired(String token) {
        Date expiration = getExpireFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * 获取token的过期时间
     *
     * @param token token
     * @return 过期时间
     */
    public Date getExpireFromToken(String token) {
        return getClaimsFromToken(token).getExpiration();
    }

    /**
     * SecretKey 根据 SECRET 的编码方式解码后得到：
     * Base64 编码：SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));
     * Base64URL 编码：SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(secretString));
     * 未编码：SecretKey key = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8));
     */
    private static SecretKey getSecretKey() {
        byte[] encodeKey = Decoders.BASE64.decode(JwtContants.SECRET);
        return Keys.hmacShaKeyFor(encodeKey);
    }

    /**
     * 用claims生成token
     *
     * @param claims 数据声明，用来创建payload的私有声明，subject只是claims的一部分
     * @return token 令牌
     */
    private String getJwtBuilder(Map<String, Object> claims) {
        SecretKey key = getSecretKey();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        return Jwts.builder()
                .claims(claims)
                .expiration(new Date(System.currentTimeMillis() + 3600 * 1000))
                .signWith(key, Jwts.SIG.HS256)
                .compact();
    }
}